package com.zg.system.auth;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zg.common.auth.ThirdCall;
import com.zg.common.core.R;
import com.zg.common.core.User;
import com.zg.common.core.dao.auth.AuthUser;
import com.zg.common.core.dao.auth.AuthUserDao;
import com.zg.common.core.util.JsonUtil;
import com.zg.common.core.util.PwdUtil;
import com.zg.common.core.util.RsaUtil;
import com.zg.common.core.util.TokenUtil;
import com.zg.common.log.LogRequest;
import com.zg.common.log.OpTypeEnum;
import com.zg.common.web.Req;
import com.zg.system.auth.req.SsoCheckReq;
import com.zg.system.auth.req.SsoLoginReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author Zxb
 */
@RestController
@RequiredArgsConstructor
@Slf4j
@RefreshScope
public class TokenController {
    private final AuthUserDao userDao;

    @Value("${sso.rsaPubKey}")
    private String rsaPubKey;
    @Value("${sso.apiBaseUrl}")
    private String apiBaseUrl;

    @PostMapping("/un/token/create")
    @LogRequest(opModule = "会话管理", opName = "登录", opType = OpTypeEnum.LOGIN)
    public R createToken(@RequestBody User u) {
        if (StrUtil.isBlank(u.getUsername())) {
            return R.error("用户名不能为空！");
        }
        if (StrUtil.isBlank(u.getPassword())) {
            return R.error("密码不能为空！");
        }
        AuthUser user = userDao.getOne(
                new LambdaQueryWrapper<AuthUser>()
                        .eq(AuthUser::getUsername, u.getUsername())
                        .eq(AuthUser::getPassword, u.getPassword()));
        if (user == null) {
            return R.error("用户名密码错误");
        }
        if (!user.getIsOpen()) {
            return R.error("用户被禁用");
        }
        u.setId(user.getId());
        u.setName(user.getName());
        u.setIsOpen(user.getIsOpen());
        u.setType(user.getType());
        String token = TokenUtil.createToken(u);
        user.setLastLoginTime(DateUtil.date().toTimestamp());
        userDao.updateById(user);
        return R.success(token);
    }

    @PostMapping("/un/cas")
    @ThirdCall
    @LogRequest(opModule = "会话管理", opName = "cas登录", opType = OpTypeEnum.LOGIN)
    public R cas(@RequestBody User u) {
        log.info("单点登录，用户名：", u.getUsername());
        if (StrUtil.isBlank(u.getUsername())) {
            return R.error("用户名不能为空！");
        }
        AuthUser user = userDao.getOne(
                new LambdaQueryWrapper<AuthUser>()
                        .eq(AuthUser::getUsername, u.getUsername()));
        if (user == null) {
            user = new AuthUser();
            user.setUsername(u.getUsername());
            user.setName(u.getUsername());
            user.setPassword(PwdUtil.generateDefaultPwd());
            user.setIsOpen(true);
            user.setIsTest(false);
            userDao.save(user);
        }
        u.setId(user.getId());
        u.setName(user.getName());
        u.setIsOpen(user.getIsOpen());
        String token = TokenUtil.createToken(u);
        return R.success(token);
    }

    @PostMapping("/token/remove")
    @LogRequest(opModule = "会话管理", opName = "注销", opType = OpTypeEnum.LOGOUT)
    public R removeToken() {
        return R.success();
    }

    @PostMapping("/un/sso")
    public R ssoLogin(@RequestBody SsoLoginReq req) {
        RestTemplate restTemplate = new RestTemplate();
        try {
            String password = RsaUtil.decrypt2(java.net.URLDecoder.decode(req.getPasswd()));
            String casPwd = RsaUtil.encryptByPub(rsaPubKey, password);
            // 获取ip
            String ipAddress = Req.getIp();
            // 设置headers
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            //form参数
            Map<String, Object> initParam = new LinkedHashMap<>();
            initParam.put("system", req.getSystem());
            initParam.put("login_timestamp", System.currentTimeMillis());
            initParam.put("loginId", req.getUsername());
            initParam.put("user_pwd", casPwd);
            initParam.put("ipAddress", ipAddress);
            // base64加密
            String encode = Base64.getEncoder().encodeToString(JSONObject.toJSONString(initParam).getBytes());
            Map<String, Object> param = new LinkedHashMap<>();
            param.put("secretContent", encode);
            //设置请求实体
            HttpEntity formRequestEntity = new HttpEntity<>(param, headers);
            ResponseEntity<ObjectNode> post = restTemplate.postForEntity(apiBaseUrl + "/user-center/rest/sso/oauth/getToken", formRequestEntity, ObjectNode.class);
            //输出返回值
            System.out.println(JsonUtil.OM.writeValueAsString(post.getBody()));
            ObjectNode on = post.getBody();
            if (on.get("code").asInt() == 200) {
                return R.success(on.get("data").get("access_token").asText());
            } else {
                return R.error(on.get("msg").asText());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("请求接口异常");
        }
    }

    @PostMapping("/un/sso/check")
    public R ssoCheck(@RequestBody SsoCheckReq req) {
        String ssoToken = req.getSsoToken();
        RestTemplate restTemplate = new RestTemplate();
        try {
            ResponseEntity<ObjectNode> request = restTemplate.getForEntity(apiBaseUrl + "/user-center/rest/sso/oauth/checkAccessToken?access_token=" + ssoToken, ObjectNode.class);
            //输出返回值
            System.out.println(JsonUtil.OM.writeValueAsString(request.getBody()));
            ObjectNode on = request.getBody();
            if (on.get("code").asInt() == 200) {
                return R.success();
            } else {
                return R.error(on.get("msg").asText());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("校验中台token过程发生异常");
        }
    }
}
